// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 此文件实现int到string的转换函数。

package big

import (
	"errors"
	"fmt"
	"io"
)

// Text返回给定基中x的字符串表示形式。
// 基数必须介于2和62之间（含2和62）。结果使用
// 小写字母“a”到“z”表示数字值10到35，
// 大写字母“a”到“z”表示数字值36到61。
// 字符串中未添加前缀（如“0x”）。如果x是nil 
// 指针，它将返回“<nil>”。
func (x *Int) Text(base int) string {
	if x == nil {
		return "<nil>"
	}
	return string(x.abs.itoa(x.neg, base))
}

// Append将由
// x.Text（base）生成的x的字符串表示形式追加到buf，并返回扩展缓冲区。
func (x *Int) Append(buf []byte, base int) []byte {
	if x == nil {
		return append(buf, "<nil>"...)
	}
	return append(buf, x.abs.itoa(x.neg, base)...)
}

// String返回由
// x.Text（10）生成的x的十进制表示形式。
func (x *Int) String() string {
	return x.Text(10)
}

// 将文本的计数副本写入s 
func writeMultiple(s fmt.State, text string, count int) {
	if len(text) > 0 {
		b := []byte(text)
		for ; count > 0; count-- {
			s.Write(b)
		}
	}
}

var _ fmt.Formatter = intOne // /*Int必须实现fmt。格式化程序

// 格式化程序实现fmt.Formatter。它接受格式
// /'b'（二进制）、'o'（八进制带0前缀）、'o'（八进制带0前缀）、
// /'d'（十进制）、'x'（小写十六进制）和
// /'x'（大写十六进制）。
// 还支持完整的fmt包格式
// 整型标志，包括符号
// 控件、#表示八进制前导零，十六进制
// 分别表示“%#x”和“%#x”的前导“0x”或“0x”，
// 最小数字精度规范，输出字段
// 宽度、空格或零填充，左或右
// 对正。
// 
func (x *Int) Format(s fmt.State, ch rune) {
	// 确定基本
	var base int
	switch ch {
	case 'b':
		base = 2
	case 'o', 'O':
		base = 8
	case 'd', 's', 'v':
		base = 10
	case 'x', 'X':
		base = 16
	default:
		// 未知格式
		fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
		return
	}

	if x == nil {
		fmt.Fprint(s, "<nil>")
		return
	}

	// 确定符号字符
	sign := ""
	switch {
	case x.neg:
		sign = "-"
	case s.Flag('+'): // 在两个指定
		sign = "+"
	case s.Flag(' '):
		sign = " "
	}

	// 确定用于指示输出基本
	prefix := ""
	if s.Flag('#') {
		switch ch {
		case 'b': // 二进制
			prefix = "0b"
		case 'o': // 八进制
			prefix = "0"
		case 'x': // 十六进制
			prefix = "0x"
		case 'X':
			prefix = "0X"
		}
	}
	if ch == 'O' {
		prefix = "0o"
	}

	digits := x.abs.utoa(base)
	if ch == 'X' {
		// 快于字节数。ToUpper 
		for i, d := range digits {
			if 'a' <= d && d <= 'z' {
				digits[i] = 'A' + (d - 'a')
			}
		}
	}

	// 三类数字填充的字符数
	var left int  // 在数字的左边留出空格以进行右对齐（“%8d”）
	var zeros int // 零个字符（实际上是cs[0]）作为最左边的数字（“%.8d”）
	var right int // 左对齐数字右侧的空格字符（“%8d”）

	// 根据精度确定数字填充：要输出的最小位数
	precision, precisionSet := s.Precision()
	if precisionSet {
		switch {
		case len(digits) < precision:
			zeros = precision - len(digits) // 零填充计数
		case len(digits) == 1 && digits[0] == '0' && precision == 0:
			return // 如果值为零值（x==0）且精度为零（“.or.”0），则不打印任何内容
		}
	}

	// 从宽度确定字段填充：要输出的最小字符数
	length := len(sign) + len(prefix) + zeros + len(digits)
	if width, widthSet := s.Width(); widthSet && length < width { // 按照指定的填充
		switch d := width - length; {
		case s.Flag('-'):
			// 在右边填充空格；当同时指定
			right = d
		case s.Flag('0') && !precisionSet:
			// 用零填充时取代“0”，除非精度也指定
			zeros = d
		default:
			// 在左侧填充空格
			left = d
		}
	}

	// 将数字打印为[左填充][符号][前缀][零填充][数字][右填充]
	writeMultiple(s, " ", left)
	writeMultiple(s, sign, 1)
	writeMultiple(s, prefix, 1)
	writeMultiple(s, "0", zeros)
	s.Write(digits)
	writeMultiple(s, " ", right)
}

// 扫描将z设置为与最长前缀
// 对应的整数值，从表示给定转换基中有符号整数的r读取。
// 返回z，即实际使用的转换基数，如果有错误，则返回一个错误。在
// 错误情况下，z的值未定义，但返回值为零。
// 语法遵循Go中整数文本的语法。
// 
// 基参数必须为0或从2到MaxBase的值。如果基础
// 为0，则字符串前缀确定实际转换基础。
// /`0b'或`0b'的前缀选择基数2；“0”、“0o”或“0o”前缀选择
// base 8，“0x”或“0x”前缀选择base 16。否则选择的
// 基数为10。
// 
func (z *Int) scan(r io.ByteScanner, base int) (*Int, int, error) {
	// 确定符号
	neg, err := scanSign(r)
	if err != nil {
		return nil, 0, err
	}

	// 确定尾数
	z.abs, base, _, err = z.abs.scan(r, base, false)
	if err != nil {
		return nil, base, err
	}
	z.neg = len(z.abs) > 0 && neg // 0没有符号

	return z, base, nil
}

func scanSign(r io.ByteScanner) (neg bool, err error) {
	var ch byte
	if ch, err = r.ReadByte(); err != nil {
		return false, err
	}
	switch ch {
	case '-':
		neg = true
	case '+':
		// 无事
	default:
		r.UnreadByte()
	}
	return
}

// byteReader是fmt.ScanState的本地包装器；
// 实现了ByteReader接口。
type byteReader struct {
	fmt.ScanState
}

func (r byteReader) ReadByte() (byte, error) {
	ch, size, err := r.ReadRune()
	if size != 1 && err == nil {
		err = fmt.Errorf("invalid rune %#U", ch)
	}
	return byte(ch), err
}

func (r byteReader) UnreadByte() error {
	return r.UnreadRune()
}

var _ fmt.Scanner = intOne // /*Int必须实现fmt.Scanner 

// 扫描是fmt.Scanner的一个支持例程；它将z设置为
// 扫描号码的值。它接受格式“b”（二进制）、“o”（八进制）、
// /“d”（十进制）、“x”（小写十六进制）和“x”（大写十六进制）。
func (z *Int) Scan(s fmt.ScanState, ch rune) error {
	s.SkipSpace() // 跳过前导空格字符
	base := 0
	switch ch {
	case 'b':
		base = 2
	case 'o':
		base = 8
	case 'd':
		base = 10
	case 'x', 'X':
		base = 16
	case 's', 'v':
		// 让扫描确定基本
	default:
		return errors.New("Int.Scan: invalid verb")
	}
	_, _, err := z.scan(byteReader{s}, base)
	return err
}
